package com.ruoyi.safe.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.entity.CommonCheckType;
import com.ruoyi.common.core.domain.entity.ListType;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.ListTypeNameEnum;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.safe.domain.BizDutyRegion;
import com.ruoyi.safe.domain.BizExcludePlanTask;
import com.ruoyi.safe.domain.BizExcludeRegion;
import com.ruoyi.safe.domain.BizExcludeUser;
import com.ruoyi.safe.domain.dto.BizExcludePlanTaskDTO;
import com.ruoyi.safe.domain.vo.*;
import com.ruoyi.safe.mapper.*;
import com.ruoyi.safe.service.IBizExcludePlanTaskService;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 自动生成任务Service业务层处理
 *
 * @author buxi
 * @date 2023-11-23
 */
@Service
@AllArgsConstructor
public class BizExcludePlanTaskServiceImpl implements IBizExcludePlanTaskService {

    private final BizExcludePlanTaskMapper bizExcludePlanTaskMapper;

    private final CommonCheckTypeMapper commonCheckTypeMapper;

    private final SysUserRoleMapper sysUserRoleMapper;

    private final BizExcludePlanMapper bizExcludePlanMapper;

    private final BizDutyRegionMapper bizDutyRegionMapper;

    private final ListTypeMapper listTypeMapper;

    private final SysUserMapper sysUserMapper;

    private final RedisCache redisCache;


    /**
     * 查询自动生成任务列表
     *
     * @param bizExcludePlanTask 自动生成任务
     * @return 自动生成任务
     */
    @Override
    public List<BizExcludePlanTask> selectBizExcludePlanTaskList(BizExcludePlanTask bizExcludePlanTask) {
        List<SysUser> sysUsers = sysUserMapper.selectUserList(new SysUser());
        List<BizExcludePlanTask> bizExcludePlanTasks = bizExcludePlanTaskMapper.selectBizExcludePlanTaskList(bizExcludePlanTask);
        bizExcludePlanTasks.forEach(bizExcludePlanTask1 -> {
            bizExcludePlanTask1.setDateRange(new Date[]{bizExcludePlanTask1.getStartDate(), bizExcludePlanTask1.getEndDate()});
            List<String> userNames = Arrays.asList(bizExcludePlanTask1.getUserName().split(","));
            bizExcludePlanTask1.setUserName(sysUsers.stream()
                    .filter(sysUser -> userNames.contains(sysUser.getUserName()))
                    .map(SysUser::getNickName)
                    .collect(Collectors.joining(",")));
        });
        return bizExcludePlanTasks;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> insertBizExcludePlanTaskBatch(BizExcludePlanTaskDTO bizExcludePlanTaskDTO) {
        Map<String, Object> map = new HashMap<>();
        BizExcludePlanTask bizExcludePlanTask = new BizExcludePlanTask();
        bizExcludePlanTask.setProjectId(bizExcludePlanTaskDTO.getProjectId());
        // 查询所有已经生成过的任务
        List<BizExcludePlanTask> bizExcludePlanTasksHistory = bizExcludePlanTaskMapper.selectBizExcludePlanTaskList(bizExcludePlanTask);
        // 查询所有的排除计划
        List<BizExcludePlanVO> bizExcludePlanVOS = bizExcludePlanMapper.selectBizExcludePlanListVOList(bizExcludePlanTaskDTO);
        // 查询所有清单分类
//        List<ListType> listTypes = listTypeMapper.selectListTypeList(new ListType());
        // 查询可以生成任务的排除计划
        List<BizExcludePlanVO> isTrue = bizExcludePlanVOS.stream()
                .filter(bizExcludePlanVO -> "1".equals(bizExcludePlanVO.getIsTask()))
                .collect(Collectors.toList());
        // 查询不可以生成任务的排除计划
        List<BizExcludePlanVO> isFalse = bizExcludePlanVOS.stream()
                .filter(bizExcludePlanVO -> "0".equals(bizExcludePlanVO.getIsTask()))
                .collect(Collectors.toList());
        if (!isFalse.isEmpty()) {
            map.put("不可生成任务的数量为", isFalse.size());
        }
        // 查询可以生成任务的排除计划的id集合
        if (!isTrue.isEmpty()) {
            List<Long> excludePlanIds = isTrue.stream().map(BizExcludePlanVO::getId).collect(Collectors.toList());
            // 查询可以生成任务的排除计划的用户 质量系统中此处为角色
            List<BizExcludeUser> bizExcludeUsers = bizExcludePlanMapper.selectBizExcludeUserList(excludePlanIds);
            // 查询可以生成任务的排除计划的区域
//            List<BizExcludeRegion> bizDutyRegions = bizExcludePlanMapper.selectBizExcludeRegionList(excludePlanIds);

            isTrue.forEach(bizExcludePlanVO -> {
                bizExcludePlanVO.setUserIds(
                        bizExcludeUsers.stream()
                                .filter(bizExcludeUser -> bizExcludeUser.getExcludePlanId().equals(bizExcludePlanVO.getId()))
                                .map(BizExcludeUser::getUserId)
                                .collect(Collectors.toList())
                );

//                bizExcludePlanVO.setRegionIds(
//                        bizDutyRegions.stream()
//                                .filter(bizExcludeRegion -> bizExcludeRegion.getExcludePlanId().equals(bizExcludePlanVO.getId()))
//                                .map(BizExcludeRegion::getRegionId)
//                                .collect(Collectors.toList())
//                );
            });
            // 查询所有的用户,下面根据id做匹配
            List<SysUser> userList = sysUserMapper.selectUserList(new SysUser());
            // 查询所有的区域,根据项目id做查询
            BizDutyRegion bizDutyRegion = new BizDutyRegion();
            bizDutyRegion.setProjectId(bizExcludePlanTaskDTO.getProjectId());
            List<BizDutyRegion> bizDutyRegionsAll = bizDutyRegionMapper.selectBizDutyRegionList(bizDutyRegion);

            // 创建一个可以生成任务的集合
            List<BizExcludePlanTask> bizExcludePlanTasks = new ArrayList<>();

            // 遍历可以生成任务的排除计划,根据区域数量生成多个任务
            for (BizExcludePlanVO bizExcludePlanVO : isTrue) {
                for (Long id : bizExcludePlanVO.getRegionIds()) {
                    BizDutyRegion dutyRegionTask = bizDutyRegionsAll.stream()
                            .filter(r -> r.getId().equals(id))
                            .findFirst()
                            .orElse(null);  // 如果没有找到,则返回null
                    // 创建一个可以生成任务的对象,并赋值
                    BizExcludePlanTask excludePlanTask = new BizExcludePlanTask();
                    // 用util复制属性
                    BeanUtil.copyProperties(bizExcludePlanVO, excludePlanTask);
                    //id为雪花算法生成
                    excludePlanTask.setId(IdUtil.getSnowflakeNextId());
                    //判断是手动生成还是自动生成
                    if (StringUtils.isEmpty(bizExcludePlanTaskDTO.getAutoType())) {
                        excludePlanTask.setCreateBy(SecurityUtils.getUsername());
                    } else {
                        excludePlanTask.setCreateBy(bizExcludePlanTaskDTO.getAutoType());
                    }
                    // 处理清单分类为父/子形式
//                    if (StringUtils.isNotBlank(bizExcludePlanVO.getAncestors())) {
//                        String[] split = StringUtils.split(bizExcludePlanVO.getAncestors(), ",");
//                        List<String> strings = Arrays.asList(split);
//                        String typeNames = listTypes.stream()
//                                .filter(listType -> strings.contains(listType.getTypeNo())).
//                                collect(Collectors.toList()).stream()
//                                .sorted(Comparator.comparing(ListType::getTypeNo))
//                                .map(ListType::getTypeName)
//                                .collect(Collectors.joining("/"));
//                        excludePlanTask.setTypeName(typeNames);
//                    }
                    excludePlanTask.setCreateTime(new Date());
                    excludePlanTask.setPlanId(bizExcludePlanVO.getId());
                    excludePlanTask.setProjectId(bizExcludePlanTaskDTO.getProjectId());

//                    excludePlanTask.setRegionId(id);
                    /*begin
                    此处重新梳理用户id 由于检查任务中设置的为角色信息，此处需要将角色转化为用户id
                    */
                    List<SysUser> users = sysUserRoleMapper.getSysUserByRole(bizExcludePlanVO.getUserIds().get(0));
                    /*end*/
                    // 每人生成一个检查任务
                    if (users!=null && users.size()>0) {
                        for(SysUser s:users) {
                            excludePlanTask.setUserName(s.getUserName());
                            // 生成任务的时候,需要判断是否已经生成过任务,如果有则返回计算下次排查时间
                            BizExcludePlanTask task = bizExcludePlanTasksHistory.stream()
                                    .filter(t -> t.getPlanId().equals(excludePlanTask.getPlanId()))
                                    .collect(Collectors.toList())  // 将匹配到的结果收集到一个集合
                                    .stream()
                                    .reduce((first, second) -> second)  // 取集合中的最后一个元素
                                    .orElse(null);

                            // 生成任务的时候,需要判断是否已经生成过任务,如果生成过任务,根据上次生成任务的时间计算下次排查时间
                            if (StringUtils.isNotNull(task)) {
                                // 计算下次排查时间,如果在排查结束时间之前,则生成任务
                                if (getNextTime(bizExcludePlanVO.getStartDate(), bizExcludePlanVO.getEndDate(), bizExcludePlanVO.getDateType(), bizExcludePlanVO.getExcludeFrequency(), task.getCreateTime())) {
                                    bizExcludePlanTasks.add(excludePlanTask);
                                }
                            } else {
                                // 如果没有生成过任务,则根据排查开始时间和结束时间生成任务
                                if (excludePlanTask.getCreateTime().after(bizExcludePlanVO.getStartDate()) && excludePlanTask.getCreateTime().before(bizExcludePlanVO.getEndDate())) {
                                    bizExcludePlanTasks.add(excludePlanTask);
                                }
                            }
                        }

                    }

                }
            }
            // 批量插入
            if (!bizExcludePlanTasks.isEmpty()) {
                bizExcludePlanTaskMapper.insertBizExcludePlanTaskBatch(bizExcludePlanTasks);
                map.put("可生成任务的数量为", bizExcludePlanTasks.size());
            }
        }
        return map;

    }

    /**
     * 取消允许生成任务
     *
     * @param bizExcludePlanTaskDTO 自动生成任务
     * @return map;
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> cancelBizExcludePlanTaskBatch(BizExcludePlanTaskDTO bizExcludePlanTaskDTO) {
        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isNotEmpty(bizExcludePlanTaskDTO.getListType()) && StringUtils.isNotNull(bizExcludePlanTaskDTO.getProjectId())) {
            bizExcludePlanTaskDTO.setUpdateBy(SecurityUtils.getUsername());
            List<BizExcludePlanTask> bizExcludePlanTasks = bizExcludePlanTaskMapper.selectBizExcludePlanTaskListByPlanIds(bizExcludePlanTaskDTO);
            map.put("取消成功数量为:", bizExcludePlanTaskMapper.deleteBizExcludePlanTaskByIds(bizExcludePlanTaskDTO));
            map.put("取消失败数量为:", bizExcludePlanTasks.size());
        }
        return map;

    }

    @Override
    public int selectBizExcludePlanTaskCount(ListRequestVo listRequestVo) {
        return bizExcludePlanTaskMapper.selectBizExcludePlanTaskCount(listRequestVo.getUserName(), listRequestVo.getProjectId());
    }

    @Override
    public List<CycleTypeVo> selectBizExcludePlanTaskListByListRequestVo(ListRequestVo listRequestVo) {

        // 查询所有的任务
        List<BizExcludePlanTaskVO> bizExcludePlanTaskVOS = bizExcludePlanTaskMapper.selectBizExcludePlanTaskListByUserName(listRequestVo.getUserName(), listRequestVo.getProjectId());
        // 查询所有的检查类型
        List<CommonCheckType> commonCheckTypes = commonCheckTypeMapper.selectCommonCheckTypeByParentId();

        // 字典转换

        bizExcludePlanTaskVOS.forEach(bizExcludePlanTaskVO -> {

            if (StringUtils.isNotBlank(bizExcludePlanTaskVO.getDateType())) {
                // 根据检查类型编号查询检查类型名称
                CommonCheckType commonCheckType1 = commonCheckTypes.stream()
                        .filter(commonCheckType -> commonCheckType.getCheckTypeNo().equals(bizExcludePlanTaskVO.getDateType()))
                        .findFirst()
                        .orElse(new CommonCheckType());

                bizExcludePlanTaskVO.setDateType(commonCheckType1.getCheckTypeName());
                bizExcludePlanTaskVO.setDateTypeValue(commonCheckType1.getCheckTypeNo());
            }

            if (StringUtils.isNotBlank(bizExcludePlanTaskVO.getRiskLevel())) {
                bizExcludePlanTaskVO.setRiskLevel(DictUtils.getDictLabel("list_risk_level", bizExcludePlanTaskVO.getRiskLevel()));
            }
        });

        // 返回的集合
        List<CycleTypeVo> cycleTypeVos = new ArrayList<>();

        // 根据日期类型和区域名称分组
        List<String> dateTypes = bizExcludePlanTaskVOS.stream().map(BizExcludePlanTaskVO::getDateType).distinct().collect(Collectors.toList());

        // 遍历日期类型
        dateTypes.forEach(dateType -> {

            // 创建一个返回对象
            CycleTypeVo cycleTypeVo = new CycleTypeVo();
            // 设置日期类型
            cycleTypeVo.setDateType(dateType);
            // 根据日期类型过滤
            List<String> areas = bizExcludePlanTaskVOS.stream()
                    .filter(c -> c.getDateType().equals(dateType)).map(BizExcludePlanTaskVO::getRegionName)
                    .distinct().collect(Collectors.toList());
            // 创建一个返回对象集合
            List<CycleTypeItemVo> cycleTypeItemVos = new ArrayList<>();
            //统计总数
            int count = 0;
            // 遍历区域
            for (String area : areas) {
                // 查询所有的任务
                CycleTypeItemVo cycleTypeItemVo = new CycleTypeItemVo();
                // 设置区域名称
                cycleTypeItemVo.setAreaName(area);
                // 设置区域id
                String regionId = bizExcludePlanTaskVOS.stream()
                        .filter(c -> c.getDateType().equals(dateType) && c.getRegionName().equals(area))
                        .findFirst()
                        .orElse(new BizExcludePlanTaskVO()).getRegionId();

                cycleTypeItemVo.setRegionId(regionId);
                List<BizExcludePlanTaskVO> excludePlanTaskVOS;
                // 根据日期类型和区域名称过滤
                excludePlanTaskVOS = bizExcludePlanTaskVOS.stream()
                        .filter(c -> c.getDateType().equals(dateType) && c.getRegionName().equals(area))
                        .collect(Collectors.toList());

                // 设置任务列表
                cycleTypeItemVo.setList(excludePlanTaskVOS);
                // 统计数量
                cycleTypeItemVo.setCount(excludePlanTaskVOS.size());
                // 统计总数
                count += excludePlanTaskVOS.size();
                // 添加到集合中
                cycleTypeItemVos.add(cycleTypeItemVo);
            }
            cycleTypeVo.setData(cycleTypeItemVos);
            cycleTypeVo.setCount(count);
            cycleTypeVos.add(cycleTypeVo);
        });
        return cycleTypeVos;

    }

    /**
     * 计算下次排查时间
     */
    private Boolean getNextTime(Date startDate, Date endDate, String dateType, Integer excludeFrequency, Date createTime) {
        int nextTime;
        if (StringUtils.isNotEmpty(dateType) && StringUtils.isNotNull(excludeFrequency)) {
            switch (dateType) {
                case "501":
                    //把日转成小时
                    nextTime = 24 / excludeFrequency;
                    //计算出上次生成任务的时间和当前时间的小时差
                    long between = DateUtil.between(createTime, new Date(), DateUnit.HOUR, false);
                    return nextTime <= between && new Date().before(endDate) && new Date().after(startDate);
                case "502":
                    //把周转成小时
                    nextTime = 7 * 24 / excludeFrequency;
                    //计算出上次生成任务的时间和当前时间的小时差
                    long between1 = DateUtil.between(createTime, new Date(), DateUnit.HOUR, false);
                    return nextTime <= between1 && new Date().before(endDate) && new Date().after(startDate);
                case "503":
                    //把月转成小时
                    nextTime = 30 * 24 / excludeFrequency;
                    //计算出上次生成任务的时间和当前时间的小时差
                    long between2 = DateUtil.between(createTime, new Date(), DateUnit.HOUR, false);
                    return nextTime <= between2 && new Date().before(endDate) && new Date().after(startDate);
                case "504":
                    //把季度转成小时
                    nextTime = 90 * 24 / excludeFrequency;
                    //计算出上次生成任务的时间和当前时间的小时差
                    long between3 = DateUtil.between(createTime, new Date(), DateUnit.HOUR, false);
                    return nextTime <= between3 && new Date().before(endDate) && new Date().after(startDate);
                case "505":
                    //把半年转成小时
                    nextTime = 180 * 24 / excludeFrequency;
                    //计算出上次生成任务的时间和当前时间的小时差
                    long between4 = DateUtil.between(createTime, new Date(), DateUnit.HOUR, false);
                    return nextTime <= between4 && new Date().before(endDate) && new Date().after(startDate);
                case "506":
                    //把年转成小时
                    nextTime = 365 * 24 / excludeFrequency;
                    //计算出上次生成任务的时间和当前时间的小时差
                    long between5 = DateUtil.between(createTime, new Date(), DateUnit.HOUR, false);
                    return nextTime <= between5 && new Date().before(endDate) && new Date().after(startDate);
                default:
                    break;
            }
        }
        return false;
    }

    /**
     * 递归查询所有父节点，包括自己
     */
    @Override
    public Set<Long> getParentsRegion(List<BizDutyRegion> regionList, BizDutyRegion bizDutyRegion) {

        Set<Long> regionIds = new HashSet<>();
        regionIds.add(bizDutyRegion.getId());
        if (StringUtils.isNotEmpty(regionList)) {
            regionList.forEach(region -> {
                if (region.getId().equals(bizDutyRegion.getParentId())) {
                    regionIds.addAll(getParentsRegion(regionList, region));
                }
            });
        }
        return regionIds;
    }


}
